﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public class KeyboardHook:GlobalHook
    {
        public event KeyEventHandler KeyDown;
        public event KeyEventHandler KeyUp;
        public event KeyPressEventHandler KeyPress;

        public KeyboardHook() {
            _hookType = WH_KEYBOARD_LL;
        }

        protected override int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam)
        {
            bool handled = false;
            if (nCode>-1&&(KeyDown!=null||KeyUp!=null|| KeyPress != null)) {
                KeyboardHookStruct keyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                bool control = ((GetKeyState(VK_LCONTROL)&0x80)!=0|| (GetKeyState(VK_RCONTROL) & 0x80) != 0);
                bool shift = ((GetKeyState(VK_LSHIFT) & 0x80) != 0) ||((GetKeyState(VK_RSHIFT) & 0x80) != 0);
                bool alt = ((GetKeyState(VK_LALT) & 0x80) != 0) || ((GetKeyState(VK_RALT) & 0x80) != 0);
                bool capslock = (GetKeyState(VK_CAPITAL) != 0);

                KeyEventArgs e = new KeyEventArgs((Keys)(keyboardHookStruct.vkCode | (control ? (int)Keys.Control : 0) | (shift ? (int)Keys.Shift : 0) | (alt?(int)Keys.Alt:0)));

                switch (wParam) {
                    case WM_KEYDOWN:
                    case WM_SYSKEYDOWN:
                        if (KeyDown!=null) {
                            KeyDown(this,e);
                            handled = handled || e.Handled;
                        }
                        break;
                    case WM_KEYUP:
                    case WM_SYSKEYUP:
                        if (KeyUp != null) {
                            KeyUp(this, e);
                            handled = handled || e.Handled;
                        }
                        break;
                }

                if (wParam == WM_KEYDOWN&&!handled&&!e.SuppressKeyPress&& KeyPress != null) {
                    byte[] keyState = new byte[256];
                    byte[] inBuffer = new byte[2];
                    GetKeyboardState(keyState);
                    if (ToAscii(keyboardHookStruct.vkCode,keyboardHookStruct.scanCode,keyState,inBuffer,keyboardHookStruct.flags)==1) {
                        char key = (char)inBuffer[0];
                        if ((capslock^shift)&&Char.IsLetter(key)) {
                            key = Char.ToUpper(key);
                        }
                        KeyPressEventArgs e2 = new KeyPressEventArgs(key);
                        KeyPress(this,e2);
                        handled = handled || e.Handled;
                    }
                }

            }

            if (handled)
            {
                return 1;
            }
            else {
                return CallNextHookEx(_handleToHook,nCode, wParam, lParam);
            }
        }
    }
}
